﻿using System;
using System.CodeDom;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web.Services;
using System.Web.Services.Description;
using System.Xml.Serialization;
using log4net;

namespace AgentSystem.AgentBaseFunctionality.DynamicProxy
{
    /// <summary>
    /// Service Proxy Compile unit generator.
    /// </summary>
    public class ServiceClientAssemblyGenerator
    {
        #region Private Members

        /// <summary>
        /// Logger
        /// </summary>
        private static readonly ILog log = LogManager.GetLogger(typeof(ServiceClientAssemblyGenerator));

        /// <summary>
        /// Get WSDL Read Timeout.
        /// </summary>
        private int _readTimeout = 60000;

        /// <summary>
        /// The _assembly folder path
        /// </summary>
        private string _assemblyFolderPath;
                
        #endregion

        #region Properties

        public string AssemblyFolderPath
        {
            get { return _assemblyFolderPath; }
            set
            {
                if (!string.IsNullOrEmpty(value) && File.Exists(value))
                {
                    _assemblyFolderPath = value;
                }
                else
                {
                    throw new DynamicProxyException("Could not set the assembly folder path to the provided value.");
                }
            }
        }

        /// <summary>
        /// WSDL Stream Read Timeout
        /// </summary>
        public int ReadTimeout
        {
            get { return _readTimeout; }
            set
            {
                if (value > 0)
                {
                    _readTimeout = value;
                }
                else
                {
                    _readTimeout = 60000;
                }
            }
        }

        #endregion

        /// <summary>
        /// Initializes a new instance of the <see cref="ServiceClientAssemblyGenerator"/> class.
        /// </summary>
        /// <param name="assemblyFolderPath">The assembly folder path.</param>
        public ServiceClientAssemblyGenerator(string assemblyFolderPath = null)
        {
            if(string.IsNullOrEmpty(assemblyFolderPath))
            {
                AssemblyFolderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
            }
            else
            {
                try
                {
                    AssemblyFolderPath = assemblyFolderPath;
                }
                catch (DynamicProxyException exception)
                {
                    AssemblyFolderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
                    string errorMessage = string.Format("Incorrect assemblyFolderPath. Setting the AssemblyFolderPath to {0}.", AssemblyFolderPath);
                    log.Error(errorMessage, exception);
                }
            }
        }

        public void GenerateServiceClientCompileUnit(Uri wsdlUri, ref CodeNamespace codeNamespace)
        {
            try
            {
                HttpWebRequest webRequest = HttpWebRequest.CreateHttp(wsdlUri);
                webRequest.ReadWriteTimeout = _readTimeout;

                using (HttpWebResponse webResponse = webRequest.GetResponse() as HttpWebResponse)
                {
                    ServiceDescription serviceDescription = ServiceDescription.Read(webResponse.GetResponseStream());
                    ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
                    importer.Style = ServiceDescriptionImportStyle.Client;
                    importer.AddServiceDescription(serviceDescription, null, null);
                    importer.CodeGenerationOptions = CodeGenerationOptions.GenerateNewAsync;

                    CodeCompileUnit compileUnit = new CodeCompileUnit();
                    var warnings = importer.Import(codeNamespace, compileUnit);
                    if (warnings > 0)
                    {
                        log.ErrorFormat("The ServiceDescriptionInporter did not generate the Service Client Compile Unit for {0}. {1}", wsdlUri.ToString());
                    }
                }
            }
            catch(Exception exception)
            {
                log.Error("There was an exception during GetClientAssembly.", exception);
                throw new DynamicProxyException(exception);
            }
        }
        
    }
}
